package examSchedule;

import orTree.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import java.util.Map.Entry;

import cpsc433.EnvironmentInterface;
import cpsc433.ExamSchedulePredicates;
import cpsc433.Pair;
import cpsc433.Predicate.ParamType;
import cpsc433.PredicateReader;
import predicate.*;

public class Environment extends PredicateReader implements EnvironmentInterface, ExamSchedulePredicates  {

	public String fromFile = null;
	public Solution solution = null;

	public HashMap<String, Student> listStudents;
	public HashMap<String, Instructor> listInstructor;
	public HashMap<String, Room> listRoom;
	public HashMap<String, Course> listCourse;
	public HashMap<String, Day> listDay;
	public HashMap<String, Session> listSession;
	public HashMap<String, Lecture> listLecture;



	public Environment(String name) {
		super(name);
		solution = new Solution(name, this);
		listStudents = new HashMap<String, Student>();
		listInstructor = new HashMap<String, Instructor>();
		listRoom = new HashMap<String, Room>();
		listCourse = new HashMap<String, Course>();
		listDay = new HashMap<String, Day>();
		listSession = new HashMap<String, Session>();
		listLecture = new HashMap<String, Lecture>();
	}

	@Override
	public void a_search(String search, String control, Long maxTime) {
		Node.search2(this, maxTime);
	}

	@Override
	public Solution getCurrentSolution() {
		return solution;
	}

	@Override
	public void setCurrentSolution(Solution currentSolution) {
		solution = currentSolution;
	}

	public static EnvironmentInterface get() {
		Environment env = new Environment("Environment");
		return env;
	}

	@Override
	public void a_student(String p) {
		if(!listStudents.containsKey(p))
		{	
			Student student = new Student(p);
			listStudents.put(p, student);
		}
	}

	@Override
	public boolean e_student(String p) {
		if(listStudents.containsKey(p))
			return true;
		else
			return false;
	}

	@Override
	public void a_instructor(String p) {
		if(!listInstructor.containsKey(p))
		{	
			Instructor instructor = new Instructor(p);
			listInstructor.put(p, instructor);
		}
	}

	@Override
	public boolean e_instructor(String p) {
		if(listInstructor.containsKey(p))
			return true;
		else
			return false;
	}

	@Override
	public void a_room(String p) {
		if(!listRoom.containsKey(p))
		{	
			Room room = new Room(p);
			listRoom.put(p, room);
		}
	}

	@Override
	public boolean e_room(String p) {
		if(listRoom.containsKey(p))
			return true;
		else
			return false;
	}

	@Override
	public void a_course(String p) {
		if(!listCourse.containsKey(p))
		{	
			Course course = new Course(p);
			listCourse.put(p, course);
		}

	}

	@Override
	public boolean e_course(String p) {
		if(listCourse.containsKey(p))
			return true;
		else
			return false;
	}

	@Override
	public void a_session(String p) {
		if(!listSession.containsKey(p))
		{	
			Session session = new Session(p);
			listSession.put(p, session);
		}

	}

	@Override
	public boolean e_session(String p) {
		if(listSession.containsKey(p))
			return true;
		else
			return false;
	}

	@Override
	public void a_day(String p) {
		if(!listDay.containsKey(p))
		{	
			Day day = new Day(p);
			listDay.put(p, day);
		}

	}

	@Override
	public boolean e_day(String p) {
		if(listDay.containsKey(p))
			return true;
		else
			return false;
	}

	@Override
	public void a_lecture(String c, String lec) {
		a_course(c);		
		if(!listLecture.containsKey(c + "%%%" + lec))
		{	
			Lecture lecture = new Lecture(listCourse.get(c), lec);
			listLecture.put(c + "%%%" + lec, lecture);
		}
	}

	@Override
	public boolean e_lecture(String c, String lec) {
		if(listLecture.containsKey(c + "%%%" + lec))
			return true;
		else
			return false;
	}

	@Override
	public void a_lecture(String c, String lec, String instructor, Long length) {	
		a_course(c);
		a_instructor(instructor);
		
		if(!listLecture.containsKey(c + "%%%" + lec))
		{	
			Lecture lecture = new Lecture(listCourse.get(c), lec, listInstructor.get(instructor), length);
			listLecture.put(c + "%%%" + lec, lecture);
		}
		
		if(!listInstructor.get(instructor).getListLecture().containsKey(c + "%%%" + lec)) {
			listInstructor.get(instructor).addLecture(c + "%%%" + lec, listLecture.get(c + "%%%" + lec));
		}
	}

	@Override
	public void a_instructs(String p, String c, String l) {
		a_course(c);
		a_instructor(p);
		if(!listLecture.containsKey(c + "%%%" + l))
		{	
			Lecture lecture = new Lecture(listCourse.get(c), l, listInstructor.get(p));
			listLecture.put(c + "%%%" + l, lecture);
		}
		
		if(!listInstructor.get(p).getListLecture().containsKey(c + "%%%" + l)) {
			listInstructor.get(p).addLecture(c + "%%%" + l, listLecture.get(c + "%%%" + l));
		}
	}

	@Override
	public boolean e_instructs(String p, String c, String l) {
		if(listLecture.containsKey(c + "%%%" + l))
		{
			if(listLecture.get(c + "%%%" + l).getLectureInstructor().getName() == p)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_examLength(String c, String lec, Long hours) {
		a_course(c);
		if(!listLecture.containsKey(c + "%%%" + lec))
		{	
			Lecture lecture = new Lecture(listCourse.get(c), lec, hours);
			listLecture.put(c + "%%%" + lec, lecture);
		} else {
			listLecture.get(c + "%%%" + lec).setLength(hours);
		}
	}

	@Override
	public boolean e_examLength(String c, String lec, Long hours) {
		if(listLecture.containsKey(c + "%%%" + lec))
		{
			if(listLecture.get(c + "%%%" + lec).getLength() == hours)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_roomAssign(String p, String room) {
		a_session(p);
		a_room(room);
		listRoom.get(room).addSession(listSession.get(p));
		listSession.get(p).setRoom(listRoom.get(room));
	}

	@Override
	public boolean e_roomAssign(String p, String room) {
		if(listSession.containsKey(p))
		{
			if(listSession.get(p).getSessionRoom().getName() == room)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_dayAssign(String p, String day) {
		a_session(p);
		a_day(day);
		listDay.get(day).addSession(listSession.get(p));
		listSession.get(p).setDay(listDay.get(day));
	}

	@Override
	public boolean e_dayAssign(String p, String day) {
		if(listSession.containsKey(p))
		{
			if(listSession.get(p).getSessionDay().getName() == day)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_time(String p, Long time) {
		a_session(p);
		listSession.get(p).setTime(time);
	}

	@Override
	public boolean e_time(String p, Long time) {
		if(listSession.containsKey(p))
		{
			if(listSession.get(p).getTime() == time)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_length(String p, Long length) {
		a_session(p);
		listSession.get(p).setLength(length);
	}

	@Override
	public boolean e_length(String p, Long length) {
		if(listSession.containsKey(p))
		{
			if(listSession.get(p).getLength() == length)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_at(String session, String day, Long time, Long length) {
		a_session(session);
		a_day(day);

		listDay.get(day).addSession(listSession.get(session));
		listSession.get(session).setDay(listDay.get(day));
		listSession.get(session).setTime(time);
		listSession.get(session).setLength(length);
	}

	@Override
	public boolean e_at(String session, String day, Long time, Long length) {
		if(listSession.containsKey(session))
		{
			if(listSession.get(session).getSessionDay().getName() == day &&
					listSession.get(session).getTime() == time &&
					listSession.get(session).getLength() == length)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_session(String session, String room, String day, Long time,
			Long length) {
		a_session(session);
		a_day(day);
		a_room(room);

		listRoom.get(room).addSession(listSession.get(session));
		listDay.get(day).addSession(listSession.get(session));
		listSession.get(session).setRoom(listRoom.get(room));
		listSession.get(session).setDay(listDay.get(day));
		listSession.get(session).setTime(time);
		listSession.get(session).setLength(length);
	}

	@Override
	public boolean e_session(String session, String room, String day,
			Long time, Long length) {
		if(listSession.containsKey(session))
		{
			if(listSession.get(session).getSessionDay().getName() == day &&
					listSession.get(session).getSessionRoom().getName() == room &&
					listSession.get(session).getTime() == time &&
					listSession.get(session).getLength() == length)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_enrolled(String student, String c, String l) {
		a_student(student);
		a_lecture(c,l);
		listStudents.get(student).addLecture(c + "%%%" + l, listLecture.get(c + "%%%" + l));
		listLecture.get(c + "%%%" + l).addStudent(listStudents.get(student));
	}

	@Override
	public boolean e_enrolled(String student, String c, String l) {
		if(listLecture.containsKey(c + "%%%" + l))
		{
			if(listLecture.get(c + "%%%" + l).getListStudent().containsKey(student))
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_enrolled(String student, Vector<Pair<ParamType, Object>> list) {
		a_student(student);

		for (int i = 0; i < list.size(); i = i + 2)
		{
			String lectureKey = list.get(i).getValue().toString() + "%%%" + list.get(i+1).getValue().toString();

			a_lecture(list.get(i).getValue().toString(), list.get(i+1).getValue().toString());
			listStudents.get(student).addLecture(lectureKey, listLecture.get(lectureKey));
			listLecture.get(lectureKey).addStudent(listStudents.get(student));
		}

	}

	@Override
	public void a_capacity(String r, Long cap) {
		a_room(r);
		listRoom.get(r).setCapacity(cap);
	}

	@Override
	public boolean e_capacity(String r, Long cap) {
		if(listRoom.containsKey(r))
		{
			if(listRoom.get(r).getRoomCapacity() == cap)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	@Override
	public void a_assign(String c, String lec, String session) {
		a_lecture(c, lec);
		a_session(session);

		listLecture.get(c + "%%%" + lec).setSession(listSession.get(session));
		listSession.get(session).setSessionLecture(listLecture.get(c + "%%%" + lec));
	}

	@Override
	public boolean e_assign(String c, String lec, String session) {
		if(listLecture.containsKey(c + "%%%" + lec))
		{
			if(listLecture.get(c + "%%%" + lec).getLectureSession().getName() == session)
				return true;
			else 
				return false;
		}
		else
			return false;
	}

	public void a_show(String a)
	{
		if (a.equals("")) {
			System.out.println(this.solution.toString());
		} else {

			Method m;
			try {
				m = this.getClass().getMethod(a + "ToString");
				System.out.println(m.invoke(this));
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				System.err.println(a + " : Not found !");
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}

		}
	}


	// toString 
	public String roomToString()
	{
		String toReturn = "\n\n// Rooms ****************************************";
		for (Entry<String, Room> e : listRoom.entrySet()){
			toReturn += "\nroom("+ e.getValue().getName() + ")";
			toReturn += "\ncapacity("+ e.getValue().getName() + "," + e.getValue().getRoomCapacity() + ")";
		}
		return toReturn;
	}

	public String instructorToString()
	{
		String toReturn = "// Instructors ****************************************";
		for (Entry<String, Instructor> e : listInstructor.entrySet()){
			toReturn += "\ninstructor("+ e.getKey() +")";
		}	

		return toReturn;
	}

	public String courseToString()
	{
		String toReturn = "\n\n// Courses ****************************************";
		for (Entry<String, Course> e : listCourse.entrySet()){
			toReturn += "\ncourse("+ e.getValue().getName() +")";
		}
		return toReturn;
	}

	public String lectureToString()
	{
		String toReturn = "\n\n// Lectures ****************************************";
		for (Entry<String, Lecture> e : listLecture.entrySet()){
			toReturn += "\nlecture("+ e.getValue().getCourse().getName() +"," +
					e.getValue().getName() + "," +
					e.getValue().getLectureInstructor().getName() + "," +
					e.getValue().getLength() + " )";
		}
		return toReturn;
	}

	public String studentToString()
	{
		String toReturn = "\n\n// Students ****************************************";
		for (Entry<String, Student> e : listStudents.entrySet()){
			toReturn += "\nstudent("+ e.getKey() + ")";
			toReturn += "\nenrolled("+ e.getKey() +", [";
			int i = 0;
			for(Entry<String, Lecture> l : e.getValue().getListLecture().entrySet())
			{
				toReturn += l.getValue().getCourse().getName() + "," + l.getValue().getName();

				i++;
				if(i < e.getValue().getListLecture().size())
					toReturn += ",";	

			}
			toReturn += "])";

		}	
		return toReturn;
	}

	public String dayToString()
	{
		String toReturn = "\n\n// Day ****************************************";
		for (Entry<String, Day> e : listDay.entrySet()){
			toReturn += "\nday("+ e.getValue().getName() +")";
		}
		return toReturn;
	}

	public String sessionToString()
	{
		String toReturn = "\n\n// Sessions ****************************************";
		for (Entry<String, Session> e : listSession.entrySet()){
			toReturn += "\nsession("+ e.getValue().getName() +")";
		}
		return toReturn;
	}

}
